(function(global){    
    /**
    *  Base64 encode / decode
    */ 
    function Base64() {
    	this._keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";    	        
    }    
    /**
     * public method for encoding 
     */
    Base64.prototype.encode = function (str) {
        if(typeof str !== 'string'){
            if(typeof str === 'object'){
                //兼容encode(obj, key)
                var obj = str,
                    key = arguments[1];
                if(typeof key === 'string'){
                    return obj[key] = this.encode(obj[key]);
                }
            }
            return str;
        }
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;
        str = ujs.str.utf8_encode(str);
        while (i < str.length) {
            chr1 = str.charCodeAt(i++);
            chr2 = str.charCodeAt(i++);
            chr3 = str.charCodeAt(i++);
            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;
            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }
            output = output +
            this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
            this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
        }
        return output;
    };
    
    /**
     * public method for decoding 
     */
    Base64.prototype.decode = function (str) {
        if(typeof str !== 'string'){
            return str;
        }
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;
        str = str.replace(/[^A-Za-z0-9\+\/\=]/g, "");
        while (i < str.length) {
            enc1 = this._keyStr.indexOf(str.charAt(i++));
            enc2 = this._keyStr.indexOf(str.charAt(i++));
            enc3 = this._keyStr.indexOf(str.charAt(i++));
            enc4 = this._keyStr.indexOf(str.charAt(i++));
            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;
            output = output + String.fromCharCode(chr1);
            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }
        }
        output = ujs.str.utf8_decode(output);
        return output;
    };  
    Base64.prototype.toBlob = function(base64Data, contentType, sliceSize) {        
        sliceSize = sliceSize || 1024;
        function charCodeFromCharacter(c) {
            return c.charCodeAt(0);
        }
        var byteCharacters = atob(base64Data),
            byteArrays = [];
        for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            var slice = byteCharacters.slice(offset, offset + sliceSize);
            var byteNumbers = Array.prototype.map.call(slice, charCodeFromCharacter);
            var byteArray = new Uint8Array(byteNumbers);    
            byteArrays.push(byteArray);
        }
        return new Blob( byteArrays, { 
            type: contentType || ''
        });        
    };
    Base64.prototype.toFile = function(fileBase64Str, fileType){                            
        return this.toBlob(fileBase64Str.substring(fileBase64Str.indexOf(',') + 1), fileType);
    };
    
    //----------------------------------------------------------------------------------------
    
    //TODO 老版本兼容性代码，新项目中去掉.
    //全局默认实例以方便调用。
    window.base64 = new Base64();

    //----------------------------------------------------------------------------------------    
    
    ujs.define('Base64', 'ujs.data', function(){
        return Base64;
    });
    
    ujs.define('base64', 'ujs.data', function(){
        return new Base64();
    });

})(window);